package com.cloudfun.campusshare.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.cloudfun.campusshare.common.constant.AsyncTaskBizType;
import com.cloudfun.campusshare.common.constant.AsyncTaskStatus;
import com.cloudfun.campusshare.common.constant.Code;
import com.cloudfun.campusshare.common.exception.BusinessException;
import com.cloudfun.campusshare.common.model.dto.AsyncTaskDTO;
import com.cloudfun.campusshare.entity.AsyncTaskEntity;
import com.cloudfun.campusshare.repo.AsyncTaskRepo;
import com.cloudfun.campusshare.service.AsyncTaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by CodeGenerator on 2020/06/04
 */
@Slf4j
@Service
public class AsyncTaskServiceImpl implements AsyncTaskService {

    @Autowired
    private AsyncTaskRepo asyncTaskRepo;

    @Override
    public void create(AsyncTaskDTO asyncTaskDTO) {
        AsyncTaskEntity asyncTaskEntity = new AsyncTaskEntity();
        BeanUtil.copyProperties(asyncTaskDTO, asyncTaskEntity);
        asyncTaskRepo.save(asyncTaskEntity);
        asyncTaskDTO.setId(asyncTaskEntity.getId());
    }

    @Override
    public AsyncTaskDTO create(AsyncTaskBizType bizType, String bizId, int count, Object params) {
        AsyncTaskDTO asyncTaskDTO = new AsyncTaskDTO();
        asyncTaskDTO.setStatus(AsyncTaskStatus.NEW);
        asyncTaskDTO.setActualCount(0);
        asyncTaskDTO.setExpectedCount(count);
        asyncTaskDTO.setBizType(bizType);
        asyncTaskDTO.setBizId(bizId);
        asyncTaskDTO.setParams(JSONObject.toJSONString(params));
        this.create(asyncTaskDTO);
        return asyncTaskDTO;
    }

    @Override
    public void modify(AsyncTaskDTO asyncTaskDTO) {
        if (asyncTaskDTO.getActualCount() >= asyncTaskDTO.getExpectedCount()) {
            asyncTaskDTO.setStatus(AsyncTaskStatus.TERMINAL);
        }
        AsyncTaskEntity asyncTaskEntity = asyncTaskRepo.findById(asyncTaskDTO.getId()).orElseThrow(() -> new BusinessException(Code.NODATA));
        // 如果状态已经为已取消 则忽略
        if (asyncTaskEntity.getStatus().equals(AsyncTaskStatus.CANCELED) && !asyncTaskDTO.getStatus().equals(AsyncTaskStatus.CANCELED)) {
            return;
        }
        // 如果状态已经为已中断取消 则忽略
        if (asyncTaskEntity.getStatus().equals(AsyncTaskStatus.ERROR_CANCEL) && !asyncTaskDTO.getStatus().equals(AsyncTaskStatus.ERROR_CANCEL)) {
            return;
        }
        BeanUtil.copyProperties(asyncTaskDTO, asyncTaskEntity);
        asyncTaskRepo.save(asyncTaskEntity);
    }

    @Override
    public void updateStatus(String id, AsyncTaskStatus status) {
        AsyncTaskEntity asyncTaskEntity = asyncTaskRepo.findById(id).orElseThrow(() -> new BusinessException(Code.NODATA));
        asyncTaskEntity.setStatus(status);
        asyncTaskRepo.save(asyncTaskEntity);
    }

    @Override
    public void delete(String string) {

    }

    @Override
    public AsyncTaskDTO get(String id) {
        AsyncTaskEntity taskEntity = asyncTaskRepo.findById(id).orElse(null);
        if (null == taskEntity) {
            return null;
        }
        AsyncTaskDTO dto = new AsyncTaskDTO();
        BeanUtil.copyProperties(taskEntity, dto);
        return dto;
    }

    @Override
    public AsyncTaskDTO getLast(AsyncTaskBizType bizType, String bizId) {
        AsyncTaskEntity taskEntity = asyncTaskRepo.findTopByBizTypeAndBizIdOrderByCreateTimeDesc(bizType, bizId);
        if (null == taskEntity) {
            return null;
        }
        AsyncTaskDTO dto = new AsyncTaskDTO();
        BeanUtil.copyProperties(taskEntity, dto);
        return dto;
    }

    @Override
    public List<AsyncTaskDTO> getRunnable(AsyncTaskBizType bizType) {
        List<AsyncTaskEntity> asyncTaskEntities = asyncTaskRepo.findAllByBizTypeAndStatusNotIn(bizType,
                Arrays.asList(AsyncTaskStatus.TERMINAL, AsyncTaskStatus.CANCELED, AsyncTaskStatus.ERROR_CANCEL));
        return asyncTaskEntities.stream()
                .map(entity -> {
                    AsyncTaskDTO dto = new AsyncTaskDTO();
                    BeanUtil.copyProperties(entity, dto);
                    return dto;
                }).collect(Collectors.toList());
    }

    @Override
    public List<AsyncTaskDTO> getRunnable(AsyncTaskBizType bizType, String bizId) {
        List<AsyncTaskEntity> asyncTaskEntities = asyncTaskRepo.findAllByBizTypeAndBizIdAndStatusNotIn(bizType, bizId,
                Arrays.asList(AsyncTaskStatus.TERMINAL, AsyncTaskStatus.CANCELED, AsyncTaskStatus.ERROR_CANCEL));
        return asyncTaskEntities.stream()
                .map(entity -> {
                    AsyncTaskDTO dto = new AsyncTaskDTO();
                    BeanUtil.copyProperties(entity, dto);
                    return dto;
                }).collect(Collectors.toList());
    }
}